#include "cfifo.h"
 
// 使用FreeRTOS的内存分配函数
CFIFO_Hooks global_hooks = {pvPortMalloc, vPortFree};

void CFIFO_Hooks_Init(CFIFO_Hooks* hooks)
{
    if (hooks == NULL)
    {
        /* Reset hooks */
        global_hooks.malloc_fn = malloc;
        global_hooks.free_fn = free;
        return;
    }

    global_hooks.malloc_fn = malloc;
    if (hooks->malloc_fn != NULL)
    {
        global_hooks.malloc_fn = hooks->malloc_fn;
    }

    global_hooks.free_fn = free;
    if (hooks->free_fn != NULL)
    {
        global_hooks.free_fn = hooks->free_fn;
    }
}

/**
 * @brief  Initialize the CFIFO with the specified buffer length.
 * @param  hcfifo: Pointer to the CFIFO handle.
 * @param  buffLength: Length of the buffer to be allocated for the CFIFO.
 */
void CFIFO_Init(CFIFO_TypeDef* hcfifo, uint16_t buffLength)
{
    hcfifo->headPos = 0;          //环形CFIFO头
    hcfifo->tailPos = 0;          //环形CFIFO尾，始终指向下一个写入位置（即tailPos对应的数据位是空的）
    hcfifo->buffLength = buffLength;     //环形CFIFO缓存区长度
    hcfifo->pBuff = (uint8_t*)global_hooks.malloc_fn(buffLength); //分配缓存区内存
}

/**
 * @brief  Deinitialize the CFIFO and free its resources.
 */
void CFIFO_DeInit(CFIFO_TypeDef* hcfifo)
{
    if (hcfifo->pBuff != NULL)
    {
        global_hooks.free_fn(hcfifo->pBuff); //释放缓存区内存
        hcfifo->pBuff = NULL;
        hcfifo->headPos = 0;          
        hcfifo->tailPos = 0;          
        hcfifo->buffLength = 0;
    }
}

/**
 * @brief  Get the free space in the CFIFO.
 * @note Free spece can be fully used. When the head and tail are equal, means the CFIFO is empty.
 * @param  hcfifo: Pointer to the CFIFO handle.
 * @return The number of free spaces in the CFIFO.
 */
int16_t CFIFO_Get_FreeSpace(CFIFO_TypeDef* hcfifo)
{
    int16_t freeSpace = 0; //实际可用空间-1，确保headPos和tailPos相等时，fifo为空

    if (hcfifo->tailPos >= hcfifo->headPos)
    {
        freeSpace = hcfifo->buffLength - (hcfifo->tailPos - hcfifo->headPos) - 1;
    }
    else // tailPos < headPos
    {
        freeSpace = hcfifo->headPos - hcfifo->tailPos - 1;
    }

    return freeSpace;
}

/**
 * @brief  Write data to the CFIFO.
 * @param  hcfifo: Pointer to the CFIFO handle.
 * @param  pData: Pointer to the data to be written.
 * @param  dataLength: Length of the data to be written.
 * @return The number of bytes written to the CFIFO.
 */
int16_t CFIFO_Write(CFIFO_TypeDef* hcfifo, uint8_t* pData, uint16_t dataLength)
{
    int16_t writeLength = 0;
    int16_t freeSpace = CFIFO_Get_FreeSpace(hcfifo); //始终为实际可用空间-1，确保headPos和tailPos相等时，fifo为空

    if(freeSpace < dataLength) //为实际可用空间-1，确保head和tail相等时，fifo为空
    {
        writeLength = freeSpace; //数据溢出
    }
    else //缓存区有足够的空间
    {
        writeLength = dataLength; //写入数据长度
        for (int16_t i = 0; i < writeLength; i++)
        {
            hcfifo->pBuff[hcfifo->tailPos++] = pData[i]; //将数据写入缓存区
            if (hcfifo->tailPos >= hcfifo->buffLength) //防止越界非法访问
            {
                hcfifo->tailPos = 0;
            }
        }
    }

    return writeLength;
}

/**
 * @brief  Get the number of available data in the CFIFO.
 * @param  hcfifo: Pointer to the CFIFO handle.
 * @return The number of available data in the CFIFO.
 */
int16_t CFIFO_Get_AvailableData(CFIFO_TypeDef* hcfifo)
{
    int16_t dataLength = 0; //实际可用数据长度

    if (hcfifo->tailPos >= hcfifo->headPos)
    {
        dataLength = hcfifo->tailPos - hcfifo->headPos;
    }
    else // tailPos < headPos
    {
        dataLength = hcfifo->buffLength - (hcfifo->headPos - hcfifo->tailPos);
    }

    return dataLength;
}

/**
 * @brief  Read data from the CFIFO.
 * @param  hcfifo: Pointer to the CFIFO handle.
 * @param  pReadBuffer: Pointer to the buffer where the read data will be stored.
 * @param  readBufferLength: Length of the read buffer.
 * @return The number of bytes read from the CFIFO.
 */
int16_t CFIFO_Read(CFIFO_TypeDef* hcfifo, uint8_t* pReadBuffer, uint16_t readBufferLength)
{
    int16_t readLength = 0;
    int16_t dataAvailable = CFIFO_Get_AvailableData(hcfifo); //实际可用数据长度

    if(dataAvailable > readBufferLength) 
    {
        readLength = readBufferLength; 
    }
    else
    {
        readLength = dataAvailable; //读取数据长度
        for (int16_t i = 0; i < readLength; i++)
        {
            pReadBuffer[i] = hcfifo->pBuff[hcfifo->headPos++]; //将数据读出缓存区
            if (hcfifo->headPos >= hcfifo->buffLength) //防止越界非法访问
            {
                hcfifo->headPos = 0;
            }
        }
    }

    return readLength;
}

/**
 * @brief  Peek data from the CFIFO without removing it.
 * @param  hcfifo: Pointer to the CFIFO handle.
 * @param  index: Index of the data to peek, starting from 0 to AvailableData - 1.
 * @return The data at the specified index, or 0 if the index is out of bounds.
 */
uint8_t CFIFO_Peek(CFIFO_TypeDef* hcfifo, uint16_t index)
{
    uint8_t data = 0; //要查看的数据

    if (index < CFIFO_Get_AvailableData(hcfifo))
    {
        data = hcfifo->pBuff[(hcfifo->headPos + index) % hcfifo->buffLength]; //将数据读出缓存区
    }

    return data;
}

/**
 * @brief  Pop data from the CFIFO, removing it from the buffer.
 * @param  hcfifo: Pointer to the CFIFO handle.
 * @param  dataLength: Length of the data to be popped.
 * @return 0 on success, -1 on failure.
 */
int16_t CFIFO_Pop(CFIFO_TypeDef* hcfifo, uint16_t dataLength)
{
    if (dataLength > CFIFO_Get_AvailableData(hcfifo))//实际可用数据长度
    {
        return -1;
    }
    hcfifo->headPos = (hcfifo->headPos + dataLength) % hcfifo->buffLength; //移动头指针

    return 0;
}

int16_t CFIFO_Push(CFIFO_TypeDef* hcfifo, uint16_t dataLength)
{
    int16_t writeLength = 0;

    if (dataLength > CFIFO_Get_FreeSpace(hcfifo))
    {
        writeLength = 0; //数据溢出
    }
    else{
        writeLength = dataLength; //写入数据长度
    }

    hcfifo->tailPos = (hcfifo->tailPos + dataLength) % hcfifo->buffLength; //移动尾指针, 计数数据溢出也要保证tailPos指向下一个写入位置

    return writeLength;
}